package com.game.doudizhu.core;

import com.game.doudizhu.model.*;
import com.game.doudizhu.util.CardPatternUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class AIRealGameTrainer {
    private static final Logger logger = LoggerFactory.getLogger(AIRealGameTrainer.class);
    
    // 存储实战数据
    private static class RealGameStats {
        // 玩家评分
        Map<Long, PlayerStats> playerStats = new ConcurrentHashMap<>();
        // 策略统计
        Map<String, StrategyStats> strategyStats = new ConcurrentHashMap<>();
        // 叫分统计
        Map<String, BidStats> bidStats = new ConcurrentHashMap<>();
        
        // 新增：对局节奏统计
        Map<String, RhythmStats> rhythmStats = new ConcurrentHashMap<>();
        
        // 新增：玩家风格统计
        Map<Long, PlayStyle> playStyles = new ConcurrentHashMap<>();
        
        // 新增：策略转换统计
        Map<String, TransitionStats> transitionStats = new ConcurrentHashMap<>();
    }
    
    private static class PlayerStats {
        int totalGames = 0;
        int wins = 0;
        Map<String, Integer> preferredStrategies = new HashMap<>();
        Map<Integer, Integer> bidPatterns = new HashMap<>();
        double avgHandStrength = 0;
    }
    
    private static class StrategyStats {
        int totalUses = 0;
        int successfulUses = 0;
        double avgRemainingCards = 0;
        double avgHandStrength = 0;
        Map<Integer, Integer> gameStageUsage = new HashMap<>();
    }
    
    private static class BidStats {
        int totalBids = 0;
        int successfulBids = 0;
        double avgHandStrength = 0;
        Map<Integer, Integer> bidValues = new HashMap<>();
    }
    
    private static class RhythmStats {
        double avgTurnDuration = 0;
        Map<Integer, Integer> cardCountDistribution = new HashMap<>();
        List<Integer> playPatterns = new ArrayList<>();
    }
    
    private static class PlayStyle {
        double aggressiveness = 0;  // 进攻性
        double conservativeness = 0;  // 保守性
        double flexibility = 0;  // 灵活性
        Map<String, Double> patternPreferences = new HashMap<>();  // 牌型偏好
    }
    
    private static class TransitionStats {
        String fromStrategy;
        String toStrategy;
        int count = 0;
        double successRate = 0;
    }
    
    private static RealGameStats gameStats = new RealGameStats();
    
    /**
     * 记录实战对局数据
     */
    public static void recordGamePlay(GameRecord gameRecord) {
//        // 更新玩家统计
//        updatePlayerStats(gameRecord);
//        // 更新策略统计
//        updateStrategyStats(gameRecord);
//        // 更新叫分统计
//        updateBidStats(gameRecord);
//        // 更新对局节奏统计
//        updateRhythmStats(gameRecord);
//        // 更新玩家风格统计
//        updatePlayStyle(gameRecord);
//        // 更新策略转换统计
//        updateTransitionStats(gameRecord);
//        // 保存学习到的策略
//        saveLearnedStrategies();
    }
    
    /**
     * 更新玩家统计
     */
    private static void updatePlayerStats(GameRecord gameRecord) {
        for (PlayerAction action : gameRecord.getActions()) {
            PlayerStats stats = gameStats.playerStats
                .computeIfAbsent(action.getPlayerId(), k -> new PlayerStats());
            
            // 更新游戏场次和胜率
            stats.totalGames++;
            if (action.isWinner()) {
                stats.wins++;
            }
            
            // 更新策略偏好
            if (action.getPlayedCards() != null && !action.getPlayedCards().isEmpty()) {
                String strategy = determineStrategy(action.getPlayedCards(), 
                    action.getLastPlayedCards(), 
                    action.isLandlord());
                stats.preferredStrategies.merge(strategy, 1, Integer::sum);
            }
            
            // 更新叫分模式
            if (action.getBidValue() >= 0) {
                stats.bidPatterns.merge(action.getBidValue(), 1, Integer::sum);
            }
            
            // 更新平均手牌强度
            stats.avgHandStrength = (stats.avgHandStrength * (stats.totalGames - 1) + 
                action.getHandStrength()) / stats.totalGames;
        }
    }
    
    /**
     * 更新策略统计
     */
    private static void updateStrategyStats(GameRecord gameRecord) {
        for (PlayerAction action : gameRecord.getActions()) {
            if (action.getPlayedCards() == null || action.getPlayedCards().isEmpty()) {
                continue;
            }
            
            String strategy = determineStrategy(action.getPlayedCards(), 
                action.getLastPlayedCards(), 
                action.isLandlord());
            
            StrategyStats stats = gameStats.strategyStats
                .computeIfAbsent(strategy, k -> new StrategyStats());
            
            stats.totalUses++;
            if (action.isWinner()) {
                stats.successfulUses++;
            }
            
            // 更新平均剩余牌数
            stats.avgRemainingCards = (stats.avgRemainingCards * (stats.totalUses - 1) + 
                action.getRemainingCards()) / stats.totalUses;
            
            // 更新平均手牌强度
            stats.avgHandStrength = (stats.avgHandStrength * (stats.totalUses - 1) + 
                action.getHandStrength()) / stats.totalUses;
            
            // 更新游戏阶段使用情况
            int gameStage = AIStrategy.getGameStage(action.getRemainingCards());
            stats.gameStageUsage.merge(gameStage, 1, Integer::sum);
        }
    }
    
    /**
     * 更新叫分统计
     */
    private static void updateBidStats(GameRecord gameRecord) {
        for (PlayerAction action : gameRecord.getActions()) {
            if (action.getBidValue() < 0) {
                continue;
            }
            
            String strengthKey = String.format("STRENGTH_%d", 
                (action.getHandStrength() / 10) * 10);
            
            BidStats stats = gameStats.bidStats
                .computeIfAbsent(strengthKey, k -> new BidStats());
            
            stats.totalBids++;
            if (action.isWinner()) {
                stats.successfulBids++;
            }
            
            // 更新平均手牌强度
            stats.avgHandStrength = (stats.avgHandStrength * (stats.totalBids - 1) + 
                action.getHandStrength()) / stats.totalBids;
            
            // 更新叫分值分布
            stats.bidValues.merge(action.getBidValue(), 1, Integer::sum);
        }
    }
    
    /**
     * 更新对局节奏统计
     */
    private static void updateRhythmStats(GameRecord gameRecord) {
        String rhythmKey = gameRecord.getLandlordId() + "_" + gameRecord.getActions().size();
        RhythmStats stats = gameStats.rhythmStats.computeIfAbsent(
            rhythmKey, k -> new RhythmStats());
        
        // 分析出牌节奏
        for (int i = 0; i < gameRecord.getActions().size(); i++) {
            PlayerAction action = gameRecord.getActions().get(i);
            
            // 更新出牌数量分布
            if (action.getPlayedCards() != null) {
                stats.cardCountDistribution.merge(
                    action.getPlayedCards().size(), 1, Integer::sum);
            }
            
            // 记录出牌模式
            if (action.getPlayedCards() != null && !action.getPlayedCards().isEmpty()) {
                stats.playPatterns.add(action.getPlayedCards().size());
            }
        }
    }
    
    /**
     * 更新玩家风格统计
     */
    private static void updatePlayStyle(GameRecord gameRecord) {
        for (PlayerAction action : gameRecord.getActions()) {
            PlayStyle style = gameStats.playStyles.computeIfAbsent(
                action.getPlayerId(), k -> new PlayStyle());
            
            if (action.getPlayedCards() != null && !action.getPlayedCards().isEmpty()) {
                // 计算进攻性（使用大牌的倾向）
                double aggression = calculateAggression(action.getPlayedCards());
                style.aggressiveness = (style.aggressiveness + aggression) / 2;
                
                // 计算保守性（保留关键牌的倾向）
                double conservation = calculateConservation(
                    action.getHandCards(), action.getPlayedCards());
                style.conservativeness = (style.conservativeness + conservation) / 2;
                
                // 更新牌型偏好
                String pattern = CardPatternUtil.getPattern(action.getPlayedCards()).name();
                style.patternPreferences.merge(pattern, 1.0, Double::sum);
            }
        }
    }
    
    /**
     * 更新策略转换统计
     */
    private static void updateTransitionStats(GameRecord gameRecord) {
        for (int i = 1; i < gameRecord.getActions().size(); i++) {
            PlayerAction prev = gameRecord.getActions().get(i-1);
            PlayerAction curr = gameRecord.getActions().get(i);
            
            if (prev.getPlayedCards() != null && curr.getPlayedCards() != null &&
                !prev.getPlayedCards().isEmpty() && !curr.getPlayedCards().isEmpty()) {
                
                String fromStrategy = determineStrategy(
                    prev.getPlayedCards(), prev.getLastPlayedCards(), prev.isLandlord());
                String toStrategy = determineStrategy(
                    curr.getPlayedCards(), curr.getLastPlayedCards(), curr.isLandlord());
                
                String transitionKey = fromStrategy + "_TO_" + toStrategy;
                TransitionStats stats = gameStats.transitionStats.computeIfAbsent(
                    transitionKey, k -> new TransitionStats());
                
                stats.count++;
                if (curr.isWinner()) {
                    stats.successRate = (stats.successRate * (stats.count - 1) + 1) / stats.count;
                } else {
                    stats.successRate = (stats.successRate * (stats.count - 1)) / stats.count;
                }
            }
        }
    }
    
    /**
     * 保存学习到的策略
     */
    private static void saveLearnedStrategies() {
        AIModelPersistence.AIModel model = AIModelPersistence.loadModel();
        
        // 转换策略权重
        for (Map.Entry<String, StrategyStats> entry : gameStats.strategyStats.entrySet()) {
            StrategyStats stats = entry.getValue();
            double successRate = stats.successfulUses / (double) stats.totalUses;
            double weight = calculateStrategyWeight(successRate, stats);
            model.strategyWeights.put(entry.getKey(), weight);
            model.averageRemainingCards.put(entry.getKey(), stats.avgRemainingCards);
        }
        
        // 转换叫分模式
        for (Map.Entry<String, BidStats> entry : gameStats.bidStats.entrySet()) {
            BidStats stats = entry.getValue();
            double successRate = stats.successfulBids / (double) stats.totalBids;
            model.bidPatterns.put(entry.getKey(), calculateOptimalBid(stats));
        }
        
        AIModelPersistence.saveModel(model);
    }
    
    /**
     * 计算策略权重
     */
    private static double calculateStrategyWeight(double successRate, StrategyStats stats) {
        double weight = 1.0;
        
        // 基于胜率的权重
        weight *= (0.5 + successRate);
        
        // 基于使用频率的权重
        double usageWeight = Math.min(1.0, stats.totalUses / 1000.0);
        weight *= (0.8 + usageWeight * 0.4);
        
        // 基于手牌强度的权重
        double strengthWeight = Math.min(1.0, stats.avgHandStrength / 100.0);
        weight *= (0.8 + strengthWeight * 0.4);
        
        return Math.max(0.1, Math.min(2.0, weight));
    }
    
    /**
     * 计算最优叫分
     */
    private static double calculateOptimalBid(BidStats stats) {
        // 找出最成功的叫分值
        int bestBidValue = 0;
        int maxSuccesses = 0;
        
        for (Map.Entry<Integer, Integer> entry : stats.bidValues.entrySet()) {
            if (entry.getValue() > maxSuccesses) {
                maxSuccesses = entry.getValue();
                bestBidValue = entry.getKey();
            }
        }
        
        return bestBidValue;
    }
    
    /**
     * 确定出牌策略类型
     * @param playedCards 要出的牌
     * @param lastPlayedCards 上家出的牌
     * @param isLandlord 是否是地主
     * @return 策略标识符
     */
    private static String determineStrategy(List<Card> playedCards, List<Card> lastPlayedCards, boolean isLandlord) {
        return AIStrategy.determineStrategy(playedCards, lastPlayedCards, isLandlord);
    }
    
    /**
     * 计算出牌的进攻性
     * @param playedCards 出的牌
     * @return 进攻性得分 (0.0-1.0)
     */
    private static double calculateAggression(List<Card> playedCards) {
        if (playedCards == null || playedCards.isEmpty()) {
            return 0.0;
        }

        double aggression = 0.0;
        int totalCards = playedCards.size();
        
        // 计算大牌比例
        int highCards = 0;
        for (Card card : playedCards) {
            if (card.getWeight() >= 14) { // A及以上
                highCards++;
            }
        }
        double highCardRatio = (double) highCards / totalCards;
        
        // 计算牌型进攻性
        CardPatternUtil.CardPattern pattern = CardPatternUtil.getPattern(playedCards);
        double patternAggression;
        
        switch (pattern) {
            case ROCKET:
                patternAggression = 1.0;    // 王炸最具进攻性
                break;
            case BOMB:
                patternAggression = 0.9;    // 炸弹次之
                break;
            case AIRPLANE:
                patternAggression = 0.8;    // 飞机
                break;
            case STRAIGHT:
                patternAggression = 0.7;    // 顺子
                break;
            case TRIPLE_WITH_ONE:
            case TRIPLE_WITH_PAIR:
                patternAggression = 0.6;    // 三带
                break;
            case STRAIGHT_PAIR:
                patternAggression = 0.5;    // 连对
                break;
            case PAIR:
                patternAggression = 0.3;    // 对子
                break;
            case SINGLE:
                patternAggression = 0.2;    // 单张
                break;
            default:
                patternAggression = 0.0;
                break;
        }
        
        // 综合评分：大牌比例 * 0.6 + 牌型进攻性 * 0.4
        aggression = highCardRatio * 0.6 + patternAggression * 0.4;
        
        return Math.min(1.0, aggression);
    }

    /**
     * 计算出牌的保守性
     * @param handCards 手牌
     * @param playedCards 出的牌
     * @return 保守性得分 (0.0-1.0)
     */
    private static double calculateConservation(List<Card> handCards, List<Card> playedCards) {
        if (handCards == null || playedCards == null || handCards.isEmpty() || playedCards.isEmpty()) {
            return 0.0;
        }

        double conservation = 0.0;
        
        // 计算保留的关键牌
        List<Card> remainingCards = new ArrayList<>(handCards);
        remainingCards.removeAll(playedCards);
        
        // 检查保留的炸弹数量
        int remainingBombs = CardUtil.findBombs(remainingCards).size();
        
        // 检查是否保留王炸
        boolean hasRocket = CardUtil.hasRocket(remainingCards);
        
        // 计算保留的大牌数量
        int remainingHighCards = 0;
        for (Card card : remainingCards) {
            if (card.getWeight() >= 14) { // A及以上
                remainingHighCards++;
            }
        }
        
        // 计算出牌后的手牌质量
        double remainingStrength = AIStrategy.calculateHandStrength(remainingCards);
        double originalStrength = AIStrategy.calculateHandStrength(handCards);
        double strengthRetention = remainingStrength / originalStrength;
        
        // 计算保守性得分
        conservation = (remainingBombs * 0.2 +              // 每个炸弹贡献0.2分
                      (hasRocket ? 0.3 : 0.0) +            // 保留王炸贡献0.3分
                      (remainingHighCards * 0.1) +         // 每张大牌贡献0.1分
                      strengthRetention * 0.4);            // 手牌强度保留率贡献0.4分
        
        return Math.min(1.0, conservation);
    }
} 